/*
Web: http://www.jsForms.com
Copyright (C) 2008  Igor Demyanov (mailto:Igor.Demyanov@gmail.com)
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
jsForms.DesignMode = {
	CreateComponent: function(type, options){
		var time = new Date().valueOf();// DEBUG - start;
		var initFunctionArr = ['jsForms.ComponentCache["' + type + '"].CreateDesign = function(compName,le){'];
		if (jsForms.ComponentCache[type] == undefined) {
			var tmp = jsForms.CreateComponent(type);
			tmp.remove();
			delete(tmp);
/*			jsForms.ComponentCache[type] = {
				Constants: {},
				DebugInfo: {}
			};
			*/
		}
		delete(jsForms.ComponentCache[type].Constants);
		delete(jsForms.ComponentCache[type].DebugInfo);
		jsForms.ComponentCache[type].Constants={};
		jsForms.ComponentCache[type].DebugInfo={};

		if (!options)
		{
			options = {};
		}
		options.Design = true;
		jsForms.CreateCache_CreateVisual(type, initFunctionArr, options);
		var list = options.DesignArray;
		for (var i=0 ; i< list.length ; i++) {
			if (list[i].skip == true)
			{
				continue;
			}
			initFunctionArr.push('le['+i+'].e.Real=el'+i+';');
			if (list[i].e.isComponent == true)
			{
				initFunctionArr.push('le['+i+'].e.RealComp=ob'+i+';');
			}
			
		}
		initFunctionArr.push('o._DesignMode=true;');
		initFunctionArr.push('return o;}');
		eval(initFunctionArr.join(''));
		time = new Date().valueOf() - time;// DEBUG - start;
		jsForms.ComponentCache[type].DebugInfo.CompilationTime = time;
		var time = new Date().valueOf();// DEBUG - start;
		var obj = jsForms.ComponentCache[type].CreateDesign(type, list);
		time = new Date().valueOf() - time;// DEBUG - start;
		options.DesignRoot.RealComp=obj;
		jsForms.ComponentCache[type].DebugInfo.CreateTime = time;
		return obj;
	},
	GetProperties: function(type,node){
		var component = jsForms.Components[type];
		if (!component) {
			var s = 'Component "' + type + '" not found!';
			console.error(s);
			throw s;
		};
		var c = component._CompileInfo;
		var result = {}
		if (c && (c.Properties != undefined)) {
			for (var i in c.Properties) {
				result[i] = c.Properties[i];
			}
		}
		
		if (node)
		{
			var all = jsForms.DesignMode.GetSpecialSubNode(node,{isProperties:true});
			var all = jsForms.DesignMode.GetSpecialSubNode(all,{isKey:true});
			for (var i=0; i< all.length ; i++)
			{
				var t = all[i];
				if (t.Name == undefined) {continue;}
				if (result[t.Name] == undefined)
				{
					result[t.Name] = {
						isNotDefinedToComponent: true
					};
				}
			}
		}
		return result;
	},
	GenerateNodeName:function (node)
	{
		//function generationName(tag, attrList){
		var idA = node.Attributes["ID"];
		var classesA = node.Attributes["CLASS"];
		var name;
		if (node.isText==true)
		{
			name = '#TEXT';
		}else
		if (node.isProperties == true)
		{
			name='Properties';
		}else
		if (node.isEvents == true)
		{
			name='Events';
		}else
		if (node.isContent == true)
		{
			name = '&gt;content';
			var into = node.Attributes['INTO'];
			if (into) {
				name = name + '[' + into.value + ']';
			}
		}else
		if (node.isKey==true)
		{
			name = '&lt;KEY';
			if (node.Name != undefined) {
				 name=name + ' '+ node.Name + '"';
			}
			name = name+'&gt;';
		}else
		{
			if (node.isComponent == true) {
				name = '&lt;' + node.Type;
			}
			else {
				name = '&lt;' + node.Tag;
			}
			if (idA != undefined) {
				name = name + '#' + idA.value;
			}
			if (classesA != undefined && $.trim(classesA.value) != '') {
				name = name + '.' + classesA.value.replace((/ +/g), '.');
			}
			name = name + '&gt;';
			if (node.Name) {
				name = name + '[' + node.Name + ']';
			}
		}
		return name;
	},
	MoveElement:function(nodeTarget,nodeTo)
	{
		/*
	Item:
		 isRoot,
		 isContent,
		 contentName,
		 isText,
		 isComponent,
		 elementR,
		 elementD,
		 componentR
	 */
		if (nodeTo.isComponent == true || nodeTo.isText == true)
		{
			return false;
		}
		
		if (nodeTo.isContent == true) {
			var component =  nodeTo.Parent.RealComp;
			component.C[nodeTo.InTo].append(nodeTarget.Real);
		}
		else {
				$(nodeTo.Real).append(nodeTarget.Real);
			}
		nodeTo.appendNode(nodeTarget);
		return true;
	},
	MoveElementUpDown:function(direction,node)
	{
		var parent = node.Parent;
		if (parent == undefined)
		{
			return false;
		}
		if (!parent.Children.indexOf)
		{
			parent.Children.indexOf = jsForms.indexOf;
		}
		if (!parent.Children.swap)
		{
			parent.Children.swap = jsForms.swap;
		}
		var index = parent.Children.indexOf(node);
		if (index == -1 || (direction == 'up' && index==0)||(direction == 'down' && index==parent.Children.length-1))
		{
			return false;
		}
		
		var ie2;
		if (direction == 'up')
		{
			ie2=index-1;
			//fname='prev';
		}else
		{
			ie2=index+1;
		}
		
//		parent.Real.
		var e1 = parent.Children[index].Real;
		var e2 = parent.Children[ie2].Real;
		if (direction == 'up') {
			parent.Real.insertBefore(e1,e2);
		}else
		{
			if (ie2 == parent.Real.childNodes.length-1)
			{
				parent.Real.appendChild(e1);
			}else
			{
				var e2 = parent.Children[ie2+1].Real;
				parent.Real.insertBefore(e1,e2);
			}
		}
		parent.Children.swap(index,ie2);
		return true;
	},
	GetSpecialSubNodeEx:function(node,selector,list)
	{
		if (list == undefined)
		{
			list= [];
		}
		for (var i = 0 ; i<node.Children.length; i++)
		{
			var t = node.Children[i];
			var isOk = true;
			for (var si in selector)
			{
				if (t[si] == undefined || t[si] != selector[si])
				{
					isOk = false;
					break;
				}
			}
			if (isOk == true)
			{
				list.push(t);
			}
		}
	},
	GetSpecialSubNode:function(nodeArr,selector)
	{
		var list = [];
		if (!selector)
		{
			return list;
		}
		if (nodeArr.length == undefined)
		{
			jsForms.DesignMode.GetSpecialSubNodeEx(nodeArr,selector,list);
		}else
		{
			for (var i = 0 ; i<nodeArr.length; i++)
			{
				jsForms.DesignMode.GetSpecialSubNodeEx(nodeArr[i],selector,list);
			}
		}
		
		return list;
	},
	GetEvents: function(type,node){
		var component = jsForms.Components[type];
		if (!component) {
			var s = 'Component "' + type + '" not found!';
			console.error(s);
			throw s;
		};
		var c = component._CompileInfo;
		var result = {}
		if (c && (c.Events != undefined)) {
			for (var i in c.Events) {
				result[i] = c.Events[i];
			}
		}
		
		if (node)
		{
			var all = jsForms.DesignMode.GetSpecialSubNode(node,{isEvents:true});
			var all = jsForms.DesignMode.GetSpecialSubNode(all,{isKey:true});
			for (var i=0; i< all.length ; i++)
			{
				var t = all[i];
				if (t.Name == undefined) {continue;}
				if (result[t.Name] == undefined)
				{
					result[t.Name] = {
						isNotDefinedToComponent: true
					};
				}
			}
		}
		return result;
	},
	GetContents: function(type){
		var component = jsForms.Components[type];
		if (!component) {
			var s = 'Component "' + type + '" not found!';
			console.error(s);
			throw s;
		};
		var c = component._CompileInfo;
		var result = {}
		if (c && (c.Contents != undefined)) {
			for (var i in c.Contents) {
				result[i] = c.Contents[i];
			}
		}
		return result;
	},
	GetDOMSetting: function(node, settingName)
	{
		settingName = settingName.toUpperCase();
		switch(settingName)
		{
			case 'NAME':{
				var value = node.Name;
				if (value == '' || value == null)
				{
					value = undefined;
				};
				return {
					value: value
				}
			}
			case 'IN TO':
			{
				var value = node.InTo;
				return {
					value: value
				}
			}
			case 'TAG':
			{
				var value = node.Tag;
				return {
					value: value,
					notEmpty:true
				}
			}
			case 'TYPE':{
				var value = node.Type;
				if (value == '' || value == null)
				{
					value = undefined;
				};
				return {
					value: value,
					notEmpty:true
				}
			}
			case 'TEXT':{
				var value = node.Text;
				if (value == '' || value == null)
				{
					value = undefined;
				};
				return {
					value: value
				}
			}
		}
		return {};
	},
	RemoveDOMSetting:function(node, settingName)
	{
		settingName = settingName.toUpperCase();
		switch (settingName) {
			case 'NAME':{
				delete (node.Name);
				$(node.Real).removeAttr('name');
				return;
			}
			case 'IN TO':{
				delete (node.InTo);
				$(node.Real).removeAttr('into');
				return;
			}
			
			case 'TYPE':{
				delete (node.Type);
				//compDesign.removeAttr('type');
				return;
			}
			case 'TEXT':{
				node.Text = '';
				node.Real.nodeValue = '';
				return;
			}
		}
	},
	SetDOMSetting: function(node, settingName,value)
	{
		settingName = settingName.toUpperCase();
		switch (settingName) {
			case 'IN TO':{
				debugger;
				if (value == undefined || value == "" || value == null) {
					jsForms.DesignMode.RemoveDOMSetting(node, settingName);
				}
				else {
					node.InTo = value;
				}
				return;
			}
			case 'NAME':{
				if (value == undefined || value == "" || value == null) {
					jsForms.DesignMode.RemoveDOMSetting(node, settingName);
				}
				else {
					node.Name = value;
					$(node.Real).attr('name', value);
					if (node.RealComp)
					{
						node.RealComp._Name = value;
					}
				}
				return;
			}
			case 'TYPE':{
				if (value == undefined || value == "" || value == null) {
					jsForms.DesignMode.RemoveDOMSetting(node, settingName);
				}
				else {
					node.Type = value;
				}
				return;
			}
			case 'TAG':
			{
				throw 'Arg test';
				var parent = compDesign.parent();
				var isRoot = (parent.length == 0);
				if (isRoot)
				{
					//it is ROOT????! :)
					// what???
					jsForms.error("No change Tag for the root object");
				}
				var tmp = $('<div/>').append(compDesign.children());
				var name = compDesign[0].nodeName;
				var tmp1 = $('<div/>').append(compDesign.clone());
				var text = tmp1[0].innerHTML;
				text ='<'+value+ text.substr(1+name.length);
				if (text[text.length - 2]!='/'){
					text = text.substr(0,text.length-1-name.length)+value+'>';
				}
				tmp1[0].innerHTML= text;
				var newcompDesign = tmp1.children();
				compDesign.before(newcompDesign).remove();
				newcompDesign.append(tmp.children())
				return;
			}
			case 'TEXT':
			{
				if (value == undefined) {
					value = '';
				}
				node.Text = value;
				node.Real.nodeValue = value;
				return;
			}
		}
	},
	CreatePropertiesNode:function()
	{
		var node = new jsForms.Node();
		node.isProperties = true;
		node.Tag ='PROPERTIES';
		return node;
	},
	CreateEventsNode:function()
	{
		var node = new jsForms.Node();
		node.isEvents = true;
		node.Tag ='EVENTS';
		return node;
	},
	
	CreateEventPropertyNode:function(keyName)
	{
		var node = new jsForms.Node();
		node.Name = keyName;
		node.isKey = true;
		node.Tag ='KEY';
		return node;
	},
	GetRootComponent:function(node)
	{
		while (node.isRoot != true)
		{
			node = node.Parent;
		}
		return node.RealComp;
	},
	GetEvent: function(node, eventInfo){
		var result =
		{
			Node:node,
			Info:eventInfo
		};
		var key = jsForms.DesignMode.GetSpecialSubNode(node,{isEvents:true});
		key = jsForms.DesignMode.GetSpecialSubNode(key,{isKey:true, Name:eventInfo.Name});
		
		if (key.length == 0) {
			return result;
		}
		if (key.length > 1) {
			jsForms.log('Event:"'+eventInfo.Name+'" - dublicate detect');
		}
		key = key[0];
		var disabled = key.Attributes['DISABLE'];
		result.Disabled = (disabled != null && disabled != undefined);
		result.Value = key.Value;
		return result;
	},
	SetEvent: function(eventObject){
		if (eventObject.Value == undefined) {
			this.RemoveEvent(node,eventName);
			return;
		}
		var node = eventObject.Node;
		var all = jsForms.DesignMode.GetSpecialSubNode(node,{isEvents:true});
		if (all.length == 0) {
			all = jsForms.DesignMode.CreateEventsNode();
			node.appendNode(all);
		}else
		{
			all = all[0];
		}
		var key = jsForms.DesignMode.GetSpecialSubNode(all,{isKey:true, Name:eventObject.Info.Name});
		if (key.length == 0) {
			key = jsForms.DesignMode.CreateEventPropertyNode(eventObject.Info.Name);
			all.appendNode(key);
		}else
		{
			key= key[0];
		}
		
			key.Value = eventObject.value;
			if (node.RealComp)
			{
				var rootComp = this.GetRootComponent(node);
				//console.log('_SetEvent('+eventName+','+rootComp+','+key.Value+')');
				node.RealComp._SetEvent(eventName,rootComp,rootComp[key.Value]);
			}
		
		if (eventObject.Disabled == undefined|| eventObject.Disabled==false) {
			delete (key.Disable);
		}
		else {
			key.Disable = true;
		}
	},
	RemoveEvent: function(eventObject){
		var node = eventObject.Node;
		var key = jsForms.DesignMode.GetSpecialSubNode(node,{isEvents:true});
		key = jsForms.DesignMode.GetSpecialSubNode(key,{isKey:true, Name:eventObject.Info.Name});
		
		if (key.length == 0) {
			return;
		}
		else {
			key = key[0];
			if (key.Parent) {
				key.Parent.removeNode(key);
			}
			if (node.RealComp) {
				var rootNode = this.GetRootComponent(node);
				node.RealComp._SetEvent(eventName,undefined,undefined);
			}
		}
	},
	GetProperty: function(node, propertyInfo){
		var key = jsForms.DesignMode.GetSpecialSubNode(node,{isProperties:true});
		key = jsForms.DesignMode.GetSpecialSubNode(key,{isKey:true, Name:propertyInfo.Name});
		var result = 
		{
			Node: node,
			Info:propertyInfo
		};
		if (key.length == 0) {
			return result;
		}else
		if (key.length > 1) {
			jsForms.log('Property:"'+propertyInfo.Name+'" - dublicate detect');
		}
		key = key[0];
		result.Value = key.Value;
		var disable = key.Attributes['DISABLE'];
		if (disable)
		{
			result.Disabled = (disable.value === true);
		}
		else
		{
			result.Disabled = false;
		}
		
		var isconst = key.Attributes['CONST'];
		if (isconst)
		{
			result.Const = (isconst.value === true);
		}
		else
		{
			result.Const = false;
		}

		return result;
	},
	RemoveProperty: function(propertyObject){
		var key = jsForms.DesignMode.GetSpecialSubNode(propertyObject.Node,{isProperties:true});
		key = jsForms.DesignMode.GetSpecialSubNode(key,{isKey:true, Name:propertyObject.Info.Name});
		if (key.length == 0) {
			return;
		}else
		{
			key = key[0];
			if (key.Parent) {
				key.Parent.removeNode(key);
			}
		}
	},
	SetProperty: function(propertyObject){
		var info = propertyObject.Info;
		var propertyName = info.Name;
		if (info.Access == 'GET')
		{
			alert(node.Type+':'+propertyName+' - only read');
			return;
		}
		var node = propertyObject.Node;
		var all = jsForms.DesignMode.GetSpecialSubNode(node,{isProperties:true});
		if (all.length == 0) {
			all = jsForms.DesignMode.CreatePropertiesNode();
			node.appendNode(all);
		}else
		{
			all = all[0];
		}
		var key = jsForms.DesignMode.GetSpecialSubNode(all,{isKey:true, Name:propertyName});
		if (key.length == 0) {
			key = jsForms.DesignMode.CreateEventPropertyNode(propertyName);
			all.appendNode(key);
		}else
		{
			key= key[0];
		}
		if (propertyObject.Value == undefined) {
			jsForms.DesignMode.RemoveProperty(propertyObject);
			return;
		}
		else {
			key.Value = propertyObject.Value.toString();
			if (node.RealComp) {
				if (propertyObject.Info.Access == 'DIRECT') {
					node.RealComp._SetProperty(propertyName, key.Value);
				}
				else {
					var tmpF = node.RealComp['Set' + propertyName];
					if (tmpF == undefined) {
						alert('"Set' + propertyName + '" - not defined');
					}
					else {
						tmpF(key.Value);
					}
				}
			}
		}
		
				
		if (propertyObject.Disabled == undefined|| propertyObject.Disabled ==false) {
			delete (key.Disable);
		}
		else {
			key.Disable = true;
		}
		
		if (propertyObject.Const == undefined|| propertyObject.Const==false) {
				delete (key.Const);
		}
		else {
			key.Const = true;
		}
	},
	DeleteDOMElement:function(node)
	{
		if (!node) {
			return false;
		}
		if (node.isContent == true||node.isRoot == true || node.Parent == undefined || node.Parent.Real == undefined)
		{
			return false;
		}
		node.Parent.Real.removeChild(node.Real);
		node.Parent.removeNode(node);
		return true;
	},
	AddTag:function(node,tag)
	{
		if (!node)
		{
			return undefined;
		}
		var newTag = document.createElement(tag);
		var newNode = new jsForms.Node();
		newNode.isTag = true;
		newNode.Tag = tag.toUpperCase();
		newNode.Real = newTag;
		this.MoveElement(newNode,node)
		return newNode;
	},
	AddComponent:function(node,compType)
	{
		if (!node)
		{
			return undefined;
		}
		var newComp = jsForms.CreateComponent(compType);
		var newNode = new jsForms.Node();
		newNode.isComponent = true;
		newNode.Type = compType;
		newNode.Tag = 'COMPONENT';
		newNode.Real = newComp[0];
		newNode.RealComp = newComp;
		this.MoveElement(newNode,node);
		newComp.Init();
		return newNode;
	},
	CreateTemplate: function(root,decore){
		var template = [];
		
		function fillAttr(node)
		{
			var attrs = node.Attributes;
			if (node.Name != undefined) {
				template.push(' name="' + node.Name + '"');
			}
			for (var i in attrs)
			{
				if (i=='NAME')
				{
					continue;
				}
				var tmpA = attrs[i];
				if (tmpA)
				{
					if (tmpA.value != undefined)
					{
						template.push(' '+i+'="'+tmpA.value+'"');
					}else
					{
						template.push(' '+i);
					}
				}
			}
		}
		function fillNode(node){
			if (node.isText == true) {
				template.push(node.Text);
				return;
			}
			
			if (decore == true) {
				if (tabs != '') {
					template.push('\n');
				}
				template.push(tabs);
			}
			template.push('<');
			template.push(node.Tag);
			if (node.isTag == true) {
				fillAttr(node);
			}
			else 
				if (node.isKey == true) {
					if (node.Name != undefined) {
						template.push(' name="' + node.Name + '"');
					}
					if (node.Value != undefined) {
						template.push(' value="' + node.Value + '"');
					}
					if (node.Disable == true) {
						template.push(' disable');
					}
					if (node.Const == true) {
						template.push(' const');
					}
				}
				else 
					if (node.isEvents == true || node.isProperties == true) {
					
					}
					else 
						if (node.isComponent == true) {
							if (node.Name != undefined) {
								template.push(' name="' + node.Name + '"');
							}
							if (node.Type != undefined) {
								template.push(' type="' + node.Type + '"');
							}
							var tmpA = node.Attributes["CLASS"];
							if (tmpA && tmpA.value != undefined) {
								template.push(' class="' + tmpA.value + '"');
							}
							var tmpA = node.Attributes["ID"];
							if (tmpA && tmpA.value != undefined) {
								template.push(' id="' + tmpA.value + '"');
							}
						}
			
			if (node.Children.length != 0) {
				template.push('>');
				var childs =node.Children;
				if (decore == true)
				{
					tabs =tabs + '\t';
				}
				
				for (var i = 0; i < childs.length; i++) {
					fillNode(childs[i]);
				}
				
				if (decore == true)
				{
					tabs = tabs.substr(0, tabs.length - 1);
					template.push('\n');
					template.push(tabs);
				}
				template.push('</'+node.Tag+'>');
			}
			else {
				template.push('/>');
			}
		}
		var tabs ='';
		fillNode(root.Children[0]);
		return template.join('');
	},
	AddCSSClass:function(node,cssclass)
	{
		if (node.isText == true || cssclass == undefined)
		{
			return;
		}
		cssclass = $.trim(cssclass);
		if (cssclass == '')
		{
			return;
		}
		var tmpA = node.Attributes["CLASS"];
		if (!tmpA)
		{
			tmpA ={};
			node.Attributes["CLASS"] = tmpA;
		}
		
		if (tmpA.value == undefined) {
			tmpA.value = cssclass;
		}
		else {
			if (!jsForms.DesignMode.HasCSSClass(tmpA.value, cssclass)) {
				tmpA.value = tmpA.value + ' ' + cssclass;
			}
		}
		$(node.Real).addClass(cssclass);
	},
	HasCSSClass:function(css,csstarget)
	{
		return eval('/'+csstarget+'( |$)/').test(css);
	},
	RemoveCSSClass:function(node,cssclass)
	{
		if (node.isText == true)
		{
			return;
		}
		var tmpA = node.Attributes["CLASS"];
		if (tmpA && tmpA.value!= undefined) {
			var mask = eval('/'+cssclass+'( |$)/');
			tmpA.value = tmpA.value.replace(mask,'');
		}
		$(node.Real).removeClass(cssclass);
	},
	CreateEmptyComponent:function(type,template)
	{
		if (jsForms.Components[type])
		{
			return {error:"Component '"+type+"' found"};
		}
		jsForms.Components[type]={};
		jsForms.Templates[type]=template;
	}
};